package com.webull.information.center.carwler.common.util.news;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import javax.annotation.PostConstruct;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import com.webull.information.center.carwler.common.util.jsoup.HtmlBodyPrase;
import com.webull.information.center.carwler.common.util.jsoup.HttpJsoupClient;
import com.webull.information.center.carwler.common.util.jsoup.prase_cn.NetEase163_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_cn.Sina_CNHtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_cn.Sina_CN_tech_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_cn.Sina_TWHtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_cn.Sohu_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_en.Bloomberg_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_en.Businesswire_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_en.Prnewswire_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_en.Reuters_HtmlPrase;
import com.webull.information.center.carwler.common.util.jsoup.prase_en.Scmp_HtmlPrase;

/**
 * 原始新闻资讯解析Mapper
 * 
 * @author shimingjun
 * @date 2016年8月18日 下午2:59:52
 * @version 1.0
 * @since JDK 1.8
 */
@Component
public class NewsHtmlPraseMapper {
	private final Logger logger = LogManager.getLogger(getClass());

	/**
	 * 网址是否需要代理
	 * 
	 * @param link
	 * @return
	 * @since 0.1.0
	 */
	public Boolean getPraseProxyMode(String link) {
		HttpJsoupClient.UrlPart urlPart = HttpJsoupClient.getUrlPart(link);
		HostInfo info = findHostInfo(urlPart);
		return Optional.ofNullable(info).map(hostInfo0 -> hostInfo0.needProxy).orElse(false);
	}

	/**
	 * 查找网址对应的网页解析器
	 * 
	 * @param link
	 *            爬取的网页地址
	 * @return 可用的网页解析器
	 * @since 0.1.0
	 */
	public HtmlBodyPrase findHtmlBodyPrase(String link) {
		try {
			HttpJsoupClient.UrlPart urlPart = HttpJsoupClient.getUrlPart(link);
			// 根据名词匹配
			HostInfo info = findHostInfo(urlPart);
			final String path0 = Optional.ofNullable(urlPart.getPath()).orElse("");

			return Optional.ofNullable(info).map(hostInfo0 -> {
				for (PraseEntry praseEntry : hostInfo0.entry) {
					if (praseEntry.testPath.test(path0)) {
						return praseEntry.htmlBodyPrase;
					}
				}
				return null;
			}).orElse(null);
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
	}

	/**
	 * 网页解析器集合
	 */
	private final List<HostInfo> htmlPrasesUnits = new ArrayList<>();

	@PostConstruct
	private void initPraseUnits() {
		// host需使用小写
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testSinaTw, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Sina_TWHtmlPrase()) }));

		// 新浪cn
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testSinaFinance, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Sina_CNHtmlPrase()) }));
		// // 新浪cn科技
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testSinaTech, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Sina_CN_tech_HtmlPrase()) }));

		// // 网易全站
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testNewEase, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new NetEase163_HtmlPrase()) }));
		// // 搜狐
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testSohu, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Sohu_HtmlPrase()) }));
		//
		// // 路透
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testReuters, //
				true, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Reuters_HtmlPrase()) }));
		// // 南华早报
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testScmp, //
				true, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Scmp_HtmlPrase()) }));
		// // 彭博新闻
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testBloomberg, //
				true, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Bloomberg_HtmlPrase()) }));
		// // 美国商业资讯
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testBusinesswire, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Businesswire_HtmlPrase()) }));
		// // 美通社
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testPrnewswire, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, new Prnewswire_HtmlPrase()) }));
		// // 21世纪经济报
		htmlPrasesUnits.add(new HostInfo(NewsPredicate::testR1Caiwire, //
				false, //
				new PraseEntry[] { new PraseEntry(NewsPathPredicate::allRegex, r1CaiNewsListUitl) }));

	}

	private @Autowired R1CaiNewsListUitl r1CaiNewsListUitl;

	private HostInfo findHostInfo(HttpJsoupClient.UrlPart urlPart) {
		// HOST部分小写
		final String host = Optional.ofNullable(urlPart.getHost()).orElse("");
		for (HostInfo hostInfo : htmlPrasesUnits) {
			if (hostInfo.testHost.test(host))
				return hostInfo;
		}
		return null;
	}

	@SuppressWarnings("rawtypes")
	public static void main(String[] args) {

		NewsHtmlPraseMapper a = new NewsHtmlPraseMapper();
		a.initPraseUnits();
		Object[][] url = new Object[][] {
				new Object[] { "http://tech.sina.com.cn/i/2016-08-29/doc-ifxvixer7386338.shtml",
						Sina_CN_tech_HtmlPrase.class }, //
				new Object[] { "http://finance.sina.com.cn/chanjing/gsnews/20151203/032423916431.shtml",
						Sina_CNHtmlPrase.class }, //
				new Object[] { "http://money.163.com/12/0615/18/842EJ5LQ002526O5.html", NetEase163_HtmlPrase.class }, //
				new Object[] { "http://money.sohu.com/20160301/n438999799.shtml", Sohu_HtmlPrase.class }, //
				new Object[] { "http://www.reuters.com/article/idUSL4N1981V1", Reuters_HtmlPrase.class }, //
				new Object[] { "http://www.scmp.com/news/china/article/1105722/briefs-december-15-2012",
						Scmp_HtmlPrase.class }, //
				new Object[] {
						"http://www.bloomberg.com/news/articles/2016-08-01/china-said-to-consider-mergers-to-create-two-state-steel-giants-irbltcmf",
						Bloomberg_HtmlPrase.class },
				new Object[] { "http://www.businesswire.com/news/home/20111115006875/zh/",
						Businesswire_HtmlPrase.class }, //
				new Object[] {
						"http://www.prnewswire.com/news-releases/global-and-china-toy-industry-report-2012-186922641.html",
						Prnewswire_HtmlPrase.class }, };
		for (int i = 0; i < url.length; i++) {
			System.out.println("-->No.." + i + "-----------" + url[i][0] + "--->");
			System.out.print("-->" + a.findHtmlBodyPrase((String) url[i][0]).getClass().getSimpleName());
			// 如不匹配，则报异常
			Assert.isTrue(a.findHtmlBodyPrase((String) url[i][0]).getClass().equals((Class) url[i][1]));
			System.out.println("-- proxy model :>" + a.getPraseProxyMode((String) url[i][0] + "----------"));
		}

	}

	private class HostInfo {
		private Predicate<String> testHost;
		private Boolean needProxy;
		private PraseEntry[] entry;

		private HostInfo(Predicate<String> testHost, Boolean needProxy, PraseEntry... entry) {
			this.testHost = testHost;
			this.needProxy = needProxy;
			this.entry = entry;
		}

	}

	private class PraseEntry {
		private Predicate<String> testPath;
		private HtmlBodyPrase htmlBodyPrase;// 解析器

		private PraseEntry(Predicate<String> testPath, HtmlBodyPrase htmlBodyPrase) {
			this.testPath = testPath;
			this.htmlBodyPrase = htmlBodyPrase;
		}

	}

}
